/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2009-2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef PARAMETER_H
#define PARAMETER_H

#include <list>
#include <map>
#include <vector>

#include <boost/smart_ptr.hpp>

#include "typedefs.h"
#include "multivector.h"

namespace cnome {
class prm {
public:
    prm(): type(new token_t()), var() {}
    prm(token_t const& t): type(new token_t(t)), var() {}
    prm(token_t const& t, token_t const& v): type(new token_t(t)), var(new token_t(v)) {}
    prm(prm const& other): type(other.type), var(other.var) {}

    prm& operator=(prm const& rhs) {
        type = rhs.type;
        var = rhs.var;
        
        return *this;
    }

    token_t* get_type() const;
    void set_type(token_t const& t);
    token_t* get_var() const;
    void set_var(token_t const& t);
    void clear_var() { var.reset(); }
    bool is_var_null() const { return var; }

private:
    boost::shared_ptr<token_t> type;  // Must exist 
    mutable boost::shared_ptr<token_t> var;
};

class parameter_scope {
public:
    typedef prm prmT;
    typedef infra::multivector<prmT> prmsT;
    typedef infra::multivector<prmT>::position_type position_type;
    typedef prmsT::const_iterator const_iterator;
    typedef prmsT::const_reverse_iterator const_reverse_iterator;
    typedef prmsT::iterator iterator;
    typedef prmsT::reverse_iterator reverse_iterator;
    typedef prmsT::level_const_iterator level_const_iterator;
    typedef prmsT::level_const_reverse_iterator level_const_reverse_iterator;
    typedef prmsT::level_iterator level_iterator;
    typedef prmsT::level_reverse_iterator level_reverse_iterator;

    enum eLevel {
        previous = -1,
        current = 0,
        next = 1 
    };

    parameter_scope();
    parameter_scope(const parameter_scope&);

    parameter_scope& operator=(const parameter_scope&);
    position_type const& get_pos() const { return prmNums; }
    int get_prmLevel() const { return prmLevel; }
    int get_prmNums(eLevel level = current) const;

    void inc_level();
    void dec_level();
    static int get_level(const_iterator& it);
    static int get_level(iterator& it);
    static int get_level(const_reverse_iterator& rit);
    int get_level() const { return prmLevel; }
    void add_parameter(const token_t&);
    void add_parameter_var(const token_t&);
    void clearPrmLevel();
    void cancelLastPrm();
    void push_back();
    void pop_back();
    void clear();

    void clearVars(); // TODO: Remove this method

    level_const_iterator begin(eLevel level) const { return begin(prmLevel + static_cast<int>(level)); }
    level_const_iterator end(eLevel level) const { return end(prmLevel + static_cast<int>(level)); }
    const_iterator begin() const { return prms.begin(); }
    const_iterator end() const { return prms.end(); }
    const_reverse_iterator rbegin() const { return prms.rbegin(); }
    const_reverse_iterator rend() const { return prms.rend(); }
    level_const_iterator begin(int level) const;
    level_const_iterator end(int level) const;

    size_t size() const { return prms.size(); }
private:
    struct lstElement {
        prmsT prms;
        int prmLevel;
        position_type prmNums;
        lstElement(const prmsT& _prms,	int _prmLevel, const position_type& _prmNums) : prms(_prms), prmLevel(_prmLevel),
            prmNums(_prmNums) {}
    };

    typedef std::list<lstElement> lstprmsT;
    
    lstprmsT lstprms;

    prmsT prms;
    int prmLevel;
    position_type prmNums;

    void fromLstElement(lstElement const& _lstElement) { 
        prms = _lstElement.prms;
        prmLevel = _lstElement.prmLevel;
        prmNums = _lstElement.prmNums;
    }

    position_type get_current_pos() const;

    position_type pos_level(int level) const {
        position_type pos(get_current_pos());
        if (level > 0) {
            pos.resize(level);
        }
        else {
            pos.resize(0);
        }
        
        return pos;
    }
};

typedef parameter_scope        prmsT;
typedef prmsT::const_iterator     constItPrms;
typedef prmsT::const_reverse_iterator constRevItPrms;
typedef prmsT::iterator           itPrms;
typedef prmsT::reverse_iterator   itRevPrms;
typedef prmsT::level_const_iterator     lvlConstItPrms;
typedef prmsT::level_const_reverse_iterator lvlConstRevItPrms;
typedef prmsT::level_iterator           lvlItPrms;
typedef prmsT::level_reverse_iterator   lvlItRevPrms;
}  //  cnome

#endif // PARAMETER_H
